/** @类 逻辑类 */
export class Logic {
	constructor({
		mainer,
		viewer
	}) {
		this.listeners = {}; // 事件集
		this.mainer = mainer; // 画布
		this.viewer = viewer; // 视口 width, height
		this.scalcs = 0; // 缩放比例
		this.active = null; // 选中
		this.stages = [];
		this.wrapper = {
			lineWidth: 3, // 线段粗细
			lineColor: 'rgba(255, 255, 255, 0.5)', // 线段颜色
			backgroundColor: 'rgba(0, 0, 0, 0.5)', // 遮罩颜色
		};
		this.background = {
			src: '', // 地址
			top: 0, // 顶部距离
			left: 0, // 左侧距离
			width: 0, // 背景宽度
			height: 0, // 背景高度
		};
		this.addListener('draw', this.onDraw.bind(this));
		this.addListener('click', this.onClick.bind(this));
	}

	/** @方法 销毁内容 */
	destroy() {
		this.listeners = {};
	}

	/** @方法 加载项目 */
	load(data) {
		this.scalcs = data.scale.scaling * (this.viewer.width / data.background.width);
		this.background.height = data.background.height * this.scalcs;
		this.background.width = data.background.width * this.scalcs;
		this.background.left = Math.abs(data.background.offsetX);
		this.background.top = Math.abs(data.background.offsetY);
		this.background.src = data.background.src;
		this.stages = data.stages;
		this.wrapper = {
			...this.wrapper,
			...data.wrapper,
		};
		this.dispatch('loaded', this.background);
		// setTimeout(() => this.dispatch('draw'), 300);
		// setTimeout(() => this.dispatch('draw'), 500);
		// setTimeout(() => this.dispatch('draw'), 1000);
	}

	/** @方法 监听事件 */
	addListener(type, listener) {
		this.GetListeners(type).push(listener);
	}

	/** @方法 触发事件 */
	dispatch(type, ...args) {
		this.GetListeners(type).forEach((listener) => listener(...args));
	}

	/** @事件 触发绘制 */
	onDraw() {
		const {
			active,
			mainer,
			wrapper,
			background,
		} = this;
		// 清空画布
		mainer.globalCompositeOperation = 'source-over';
		mainer.clearRect(0, 0, background.width, background.height);
		// 绘制选中
		if (active) {
			// 绘制遮罩
			mainer.setFillStyle(wrapper.backgroundColor);
			mainer.beginPath();
			mainer.rect(0, 0, background.width, background.height);
			mainer.closePath();
			mainer.fill();
			// 地块挖孔
			mainer.setFillStyle('black');
			mainer.globalCompositeOperation = 'destination-out';
			mainer.beginPath();
			active.polygon.forEach(({ x, y }, i) => {
				i === 0 ? mainer.moveTo(this.GetVar(x), this.GetVar(y)) : mainer.lineTo(this.GetVar(x), this.GetVar(y));
			});
			mainer.closePath();
			mainer.fill();
		}
		// 通知绘制
		mainer.draw();
	}

	/** @事件 触发点击 */
	onClick(touch, offset) {
		// 计算点击位置
		const point = { x: touch.x, y: touch.y };
		point.x = (point.x + offset.left) / this.scalcs;
		point.y = (point.y + offset.top) / this.scalcs;
		console.log('------ Click', touch, offset, point);
		// 获取选中地块
		const { active, viewer } = this;
		const stage = this.GetStage(point);
		if (active) {
			// 当重新点击则取消选中
			this.active = null;
			this.dispatch('stage', {
				stage: this.active,
				top: touch.y < viewer.height / 2,
				left: touch.x < viewer.width / 2,
			});
		} else if (stage) {
			// 当未选中则设置选中
			this.active = stage;
			this.dispatch('stage', {
				stage: this.active,
				top: touch.y < viewer.height / 2,
				left: touch.x < viewer.width / 2,
			});
		}
		// 发送重绘通知
		this.dispatch('draw');
	}

	/** @辅助 计算坐标 */
	GetVar(v) {
		return v * this.scalcs;
	}

	/** @辅助 是否点击地块 */
	GetStage(point) {
		const {
			x,
			y
		} = point;
		return this.stages.find(({
			polygon
		}) => {
			let inside = false;
			for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
				const xi = polygon[i].x;
				const yi = polygon[i].y;
				const xj = polygon[j].x;
				const yj = polygon[j].y;

				if (((yi > y) !== (yj > y)) && (x < ((xj - xi) * (y - yi)) / (yj - yi) + xi)) {
					inside = !inside;
				}
			}
			return inside;
		}) || null;
	}

	/** @辅助 获取事件 */
	GetListeners(type) {
		!this.listeners[type] && (this.listeners[type] = []);
		return this.listeners[type];
	}
}

export default Logic;